package provider

import (
	"bytes"
	"fmt"
	"github.com/gin-gonic/gin"
	motan "github.com/weibocom/motan-go/core"
	vlog "github.com/weibocom/motan-go/log"
	"net/http"
	"strings"
)

type GinHandlerFunc func(*gin.Context)

type ProxyProvider struct {
	service  interface{}
	instance *gin.Engine
	methods  map[string]bool
	url      *motan.URL
}

type MotanResponseWriter struct {
	bytes.Buffer
}

func (mr *MotanResponseWriter) WriteHeader(statusCode int) {}

func (mr *MotanResponseWriter) Header() http.Header {
	return make(http.Header)
}

// NewProxyProvider create a new proxy provider
func NewProxyProvider(i *gin.Engine, url *motan.URL, m map[string]bool) *ProxyProvider {
	return &ProxyProvider{instance: i, url: url, methods: m}
}

func (d *ProxyProvider) Initialize() {
	if len(d.methods) == 0 {
		vlog.Errorf("can not init provider. proxy method is empty. service :%v, url:%v\n", d.service, d.url)
		return
	}
}

func (d *ProxyProvider) SetService(s interface{}) {
	d.service = s
}

func (d *ProxyProvider) GetURL() *motan.URL {
	return d.url
}

func (d *ProxyProvider) SetURL(url *motan.URL) {
	d.url = url
}

func (d *ProxyProvider) GetPath() string {
	return d.url.Path
}

func (d *ProxyProvider) IsAvailable() bool {
	return true
}

func (d *ProxyProvider) Destroy() {}

func (d *ProxyProvider) Call(request motan.Request) (res motan.Response) {
	var err error
	path := request.GetMethod()
	if strings.Index(path, "/") != 0 {
		path = "/" + path
	}

	var args = request.GetArguments()
	var method = request.GetAttachment("T_Method")
	//var uri = request.GetAttachment("T_Uri")

	if method == "" {
		method = "POST"
	}
	reader := &bytes.Buffer{}
	if len(args) > 0 {
		dsvp, ok := args[0].(*motan.DeserializableValue)
		if !ok {
			vlog.Errorf("arguments is not deserializable. %s\n", motan.GetReqInfo(request))
			return motan.BuildExceptionResponse(request.GetRequestID(), &motan.Exception{ErrCode: 500, ErrMsg: "arguments is not deserializable.", ErrType: motan.ServiceException})
		}
		body, err := dsvp.Deserialize(dsvp)
		if err != nil {
			vlog.Errorf("arguments deserialize error. %s\n", motan.GetReqInfo(request))
			return motan.BuildExceptionResponse(request.GetRequestID(), &motan.Exception{ErrCode: 500, ErrMsg: "arguments deserialize error.", ErrType: motan.ServiceException})
		}
		t := fmt.Sprintf("%T", body)
		var bodyStr string
		switch t {
		case "[]string":
			b := body.([]string)
			if len(b) == 0 {
				return
			}
			bodyStr = b[0]
		//case "[]uint8":
		//	b := body.([]byte)
		//	bodyStr = string(b)
		default:
			b := body.([]byte)
			bodyStr = string(b)
		}
		//log.Printf("%v,%+v,%+v", t, body, bodyStr)

		reader.Write([]byte(bodyStr))
	}
	var r *http.Request
	if r, err = http.NewRequest(method, path, reader); err != nil {
		vlog.Errorf("build gin request error. %s\n", motan.GetReqInfo(request))
		return motan.BuildExceptionResponse(request.GetRequestID(), &motan.Exception{ErrCode: 500, ErrMsg: "build gin request error.", ErrType: motan.ServiceException})
	}
	r.Header.Set("Content-Type", "application/json")
	//		r.Header.Set("T_Uri", uri)
	request.GetAttachments().Range(func(k, v string) bool {
		//log.Println(k,v)
		r.Header.Set(k, v)
		return true
	})

	w := &MotanResponseWriter{}
	d.instance.ServeHTTP(w, r)
	//strconv.ParseUint(request.GetMethodDesc(),10,31)
	mres := &motan.MotanResponse{RequestID: request.GetRequestID()}
	if w.Len() > 0 { // only use first return value.
		mres.Value = w.String()
	}
	//lib.Debugf(nil, "req:%+v,res:%+v", request, mres)

	return mres
}
